home *** CD-ROM | disk | FTP | other *** search
- ;* SCANNUM.ASM
- ;************************************************************************
- ;* *
- ;* PC Scheme/Geneva 4.00 Borland TASM code *
- ;* *
- ;* (c) 1985-1988 by Texas Instruments, Inc. See COPYRIGHT.TXT *
- ;* (c) 1992 by L. Bartholdi & M. Vuilleumier, University of Geneva *
- ;* *
- ;*----------------------------------------------------------------------*
- ;* *
- ;* Numeric I/O support *
- ;* *
- ;*----------------------------------------------------------------------*
- ;* *
- ;* Created by: John Jensen Date: 1985 *
- ;* Revision history: *
- ;* - 18 Jun 92: Renaissance (Borland Compilers, ...) *
- ;* *
- ;* ``In nomine omnipotentii dei'' *
- ;************************************************************************
- IDEAL
- %PAGESIZE 60, 132
- MODEL medium
- LOCALS @@
-
- INCLUDE "scheme.ash"
-
- DATASEG
- decpoint DB '.'
-
- CODESEG
- ;************************************************************************
- ;* Classify numeric string ending with a control character *
- ;* Calling sequence: scannum(s,base) *
- ;* Where ---- s: pointer to start of character string *
- ;* base: default base *
- ;* This function returns 0 if not a number, -1 if a flonum, and n>0 *
- ;* if an integer, where n is the number of digits in the integer. *
- ;* *
- ;* NOTE : ds is not guaranteed to point to the local data segment *
- ;* *
- ;************************************************************************
- PROC C scannum USES si, @@string:WORD, @@base:WORD
- cld
- mov si, [@@string]
- mov bx, [@@base]
- xor cx, cx ; Initialize digit count
- @@baseloop:
- lodsb
- cmp al, '#' ; skip over the base macros
- jne @@notmacro
- lodsb ; Get base argument
- sub al, 40h
- js @@notanumber ; If not a base designator, not a number
- and al, not ('a' - 'A')
- xor bl, bl ; bl will get incremented
- cmp al, 'E' - 40h
- je @@baseloop
- cmp al, 'I' - 40h
- je @@baseloop
- cmp al, 'L' - 40h
- je @@baseloop
- cmp al, 'S' - 40h
- je @@baseloop
- cmp al, 'B' - 40h
- je @@binary
- cmp al, 'D' - 40h
- je @@decimal
- cmp al, 'O' - 40h
- je @@octal
- cmp al, 'X' - 40h
- je @@hexadecimal
- cmp al, 'H' - 40h
- jne @@notanumber
- @@hexadecimal:
- mov bl, 6
- @@decimal:
- add bl, 2
- @@octal:
- add bl, 6
- @@binary:
- add bl, 2
- jmp @@baseloop ; Check for another switch
- @@notmacro:
- cmp al, '+'
- je @@skipsign
- cmp al, '-'
- jne @@notsign
- @@skipsign:
- lodsb
- @@notsign:
- cmp al, [ss:decpoint]
- je @@alreadyflonum
- call isdg
- jnc @@notanumber
- @@loop:
- lodsb
- call isdg
- jc @@loop
- cmp al, ' ' ; done ?
- jb @@itsanumber
- cmp al, [ss:decpoint]
- je @@flonum
- call ismarker
- je @@exponent
- @@notanumber:
- xor ax, ax ; Return 0, forget all else
- ret
- @@itsanumber:
- mov ax, cx ;Return digit count
- ret
- @@alreadyflonum:
- lodsb ; We must have a digit here
- call isdg
- jnc @@notanumber
- @@flonum:
- lodsb ; Get characters up to non-digit
- call isdg
- jc @@flonum
- cmp al, ' ' ; If end of string, we have flonum
- jb @@retflonum
- call ismarker ;Otherwise, check for exponent marker
- je @@exponent
- jne @@notanumber
- @@exponent:
- mov bl, 10 ; Exponents are in base 10
- lodsb
- cmp al, '-'
- jne @@skipexpsign
- lodsb
- @@skipexpsign:
- call isdg ; We must end with a nonempty string
- jnc @@notanumber
- @@exploop:
- lodsb
- call isdg
- jc @@exploop
- cmp al, ' ' ; If not end of string, it ain't no number
- jae @@notanumber
- @@retflonum:
- mov ax, -1 ; Return -1 (flonum code)
- ret
- ENDP scannum
-
- ;************************************************************************
- ;* ISDG: CF is set iff the char in al is a digit in base bx *
- ;* Also, if a digit, the digit count in cx is incremented *
- ;************************************************************************
- PROC isdg NEAR
- cmp al, '0'
- jl @@notadigit
- cmp al, '1' ; 0 or 1 anytime
- jbe @@digit
- cmp bl, 2 ; Nothing else for base 2
- je @@notadigit
- cmp al, '7' ; 2-7 for base 8, 10, 16
- jbe @@digit
- cmp bl, 8 ; Nothing else for base 8
- je @@notadigit
- cmp al, '9' ; 8 or 9 for bases 10 or 16
- jbe @@digit
- cmp bl, 10 ; Nothing else for base 10
- je @@notadigit
- and al, not ('a' - 'A')
- cmp al, 'A' ; base 16... check for A-F
- jb @@notadigit
- cmp al, 'F'
- jbe @@digit
- @@notadigit:
- clc
- ret
- @@digit:
- inc cx ; Increment digit count
- stc
- ret
- ENDP isdg
-
- ;************************************************************************
- ;* ISMARKER: ZF is set iff the character in al is an exponent marker *
- ;************************************************************************
- PROC ismarker NEAR
- IRP EXP, <'e', 'E', 'l', 'L'>
- cmp al, EXP
- je @@mark
- ENDM
- @@mark:
- ret
- ENDP ismarker
-
- ;************************************************************************
- ;* Check character for digit status in a given base *
- ;* Calling sequence: isdig(c,base) *
- ;* Where c: character to check *
- ;* base: base in which to check *
- ;************************************************************************
- PROC C isdig, @@char:WORD, @@base:WORD
- mov al, [BYTE @@char]
- mov bx, [@@base]
- call isdg
- jc @@digit ; Was a digit...don't zero ax
- xor ax, ax ; Otherwise return 0
- @@digit:
- ret
- ENDP isdig
-
- ;************************************************************************
- ;* Convert digit character to its value *
- ;* Calling sequence: digval(c) *
- ;* Where ---- c: assumed to be a digit character *
- ;************************************************************************
- PROC C digval, @@char:WORD
- mov al, [BYTE @@char]
- xor ah, ah
- and al, 1fh ; Reduce bits
- cmp al, 10h ; Number or letter?
- jb @@hexdigit
- and al, 0fh ; Zero the high nibble
- ret
- @@hexdigit:
- add al, 9 ;Raise the lower nibble
- ret
- ENDP digval
-
- ;************************************************************************
- ;* Convert flonum in interval [1.0e15,1.0e16) to bignum *
- ;* Calling sequence: flo2big(flo,buf) *
- ;* Where flo: flonum in interval [1e15,1e16) *
- ;* buf: bignum math buffer, minimum size 11 bytes *
- ;************************************************************************
- P8087
- PROC C flo2big USES si di, @@float:QWORD, @@big:WORD
- LOCAL @@status:WORD
- mov di, [@@big]
- mov [WORD di], 4 ; Store bignum size (words) in buffer
- mov [BYTE di+2], 0 ; assume positive
- fld [@@float]
- ftst
- fstsw [@@status]
- fabs
- fistp [QWORD di+3]
- mov ax, [@@status]
- sahf
- jae @@positive
- inc [BYTE di+2] ; sign is now 1
- @@positive:
- ret
- ENDP flo2big
-
- ;************************************************************************
- ;* Form floating-point ASCII representation from 16 digits and scale *
- ;* Calling sequence: formflo(digs,chars,scale,prec,exp) *
- ;* Where digs: the digit characters of the flonum *
- ;* chars: buffer to store the formed flonum *
- ;* scale: flonum exponent part *
- ;* prec: desired precision *
- ;* exp: whether to use exponential format *
- ;* Returns the length of the formed flonum string *
- ;************************************************************************
- PROC C formflo USES si di, @@digs:WORD, @@chars:WORD, $$scale:WORD, @@prec:WORD, @@exp:WORD
- push ds
- pop es
- mov si, [@@digs]
- mov di, [@@chars]
- cld
- mov dx, [@@exp]
- mov al, [si] ; Fetch first digit
- cmp al, '0'
- je @@underflow
- cmp al, '-'
- jne @@notsigned
- stosb ; Put sign in return buffer
- inc [@@digs] ; Adjust pointer to first digit
- inc si
- @@notsigned:
- mov bx, 14 ; Round off the last digit
- call round_asc
- mov bx, [@@prec] ; Fetch precision
- or bx, bx
- jz @@putalldigits
- cmp bx, 14 ; If precision out of range, replace
- jbe @@validprecision
- mov bx, 14
- @@validprecision:
- or dx, dx
- jnz @@round ; If exponential, round now
- add bx, [$$scale] ; Add scale to precision
- jns @@notsmall ; Jump unless number rounds to 0
- cmp bx, -1
- jne @@underflow ; Jump if num definitely rounds to 0
- cmp [BYTE si], '5'
- jb @@underflow
- mov [WORD si], ' 1' ; Else round up and adjust scale
- inc [$$scale]
- jmp @@doit
-
- @@underflow:
- mov al, '0' ; put (prec+1) 0's at start of input buf
- mov bx, [@@prec]
- @@underflowloop:
- mov [si], al
- inc si
- dec bl
- jns @@underflowloop
- mov [BYTE si], ' ' ; follow by space
- mov di, [@@chars] ; Start output over (wipe out any sign)
- jmp @@doit
-
- @@notsmall:
- cmp bx, 16 ; then, no need to round
- jae @@doit
- @@round:
- call round_asc
- jmp @@doit
-
- @@putalldigits: ; For arbitrary precision, change all
- ; trailing zeros to spaces (there exists at least one nonzero digit)
- add si, 14 ;Point si to last digit
- @@spaceloop:
- cmp [BYTE si], '0'
- jne @@doit
- mov [BYTE si], ' '
- dec si
- jmp @@spaceloop
- @@doit: ; Now the spaces are in - start formatting
- mov si, [@@digs] ; Point si to digit string
- mov bx, [$$scale]
- mov cx, [@@prec]
- or dx, dx ; exponent form desired ?
- jnz @@exponentform
- cmp bx, -14 ; If scale>-15, check precision
- jge @@midscale
- or cl, cl ; If arbitrary, force expo-form
- jz @@exponentform
- @@midscale:
- or bx, bx
- jl @@smallfix
- cmp bx, 14
- jle @@largefix
- @@exponentform:
- movsb ; Transfer first digit
- mov al, [decpoint]
- @@putexponent:
- stosb ; Store character
- lodsb ; Transfer digits up to first space
- cmp al, ' '
- jne @@putexponent
- mov al, 'e' ; place exponent marker
- stosb
- or bx, bx ;If scale negative, negate & store sign
- jge @@positivescale
- neg bx
- mov al, '-'
- stosb
- @@positivescale:
- mov ax, bx
- mov bh, 10
- mov dx, sp ; Save current stack pointer
- @@divideexponent:
- div bh ; Divide
- mov bl, ah ; Push digit
- add bl, '0'
- push bx
- and ax, 0ffh ; Remove the remainder
- jnz @@divideexponent
- @@storeexponent:
- pop ax ; Restore exponent digit
- stosb
- cmp sp, dx ; Loop until no more digits left
- jne @@storeexponent
- jmp @@ret
-
- ;Form a fixed-decimal flonum magnitude greater than 1
- @@largefix:
- lodsb
- or al, 10h ; Turn ' ' to '0'
- stosb
- dec bl ; Loop until all pre-point digs done
- jns @@largefix
- mov al, [decpoint]
- stosb
- @@mergedigits:
- or cl, cl
- jnz @@precisionloop
- @@arbitraryloop:
- lodsb ; Otherwise, arbitrary; do until space
- cmp al, ' '
- je @@ret
- stosb
- jmp @@arbitraryloop
- @@largeloop:
- stosb
- @@precisionloop:
- dec cl ; Last digit done?
- js @@ret
-
- lodsb ; Now do digits until precision reached
- cmp al, ' '
- jne @@largeloop
- dec si ; Restore si
- mov al, '0' ; prepare to place 0
- jmp @@largeloop
-
- ;Form a fixed-decimal flonum magnitude less than 1
- @@smallfix:
- mov ch, cl ; Copy precision to ch
- mov al, '0' ; place "0."
- stosb
- mov al, [decpoint]
- @@shortloop:
- stosb
- inc bx
- jz @@mergedigits ; If 0's done, do significant figures
- or ch, ch ; If precision was zero
- jz @@skipprec
- dec cl
- js @@ret
- @@skipprec:
- mov al, '0' ; otherwise, place 0's until scale=0
- jmp @@shortloop
-
- @@ret:
- mov ax, di ; Return length of string
- sub ax, [@@chars]
- ret
- ENDP formflo
-
- ;************************************************************************
- ;* ROUND: Round the ASCII digits of a flonum, starting at [bx+si] *
- ;* si->start of digits and is unchanged; bx destroyed *
- ;************************************************************************
- PROC round_asc NEAR
- mov al, ' ' ; get digit after least-rounded and
- xchg al, [bx+si+1] ; replace it with a space
- cmp al, '5'
- jb @@rounded
- @@loop:
- mov al, [bx+si] ; Otherwise, increment digit
- inc al
- mov [bx+si], al ; Replace incremented digit
- cmp al, '9'
- jbe @@rounded
- mov [BYTE bx+si], '0'
- dec bx ; Go to next digit
- jns @@loop
- mov [BYTE bx+si+1], '1' ; there are no more digits, place
- inc [$$scale] ; a leading 1 and adjust scale
- @@rounded:
- ret
- ENDP round_asc
-
- END
-